package com.gxljc.bear.crawler.image;

import com.gxljc.commons.util.StringUtil;
import com.gxljc.bear.crawler.base.DolphinCrawlerConf;
import net.coobird.thumbnailator.Thumbnails;
import net.coobird.thumbnailator.Thumbnails.Builder;
import net.coobird.thumbnailator.geometry.Positions;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

/**
 * 图片存储查询服务
 *
 * @author Darren Mo
 * @date 2022年11月27日 下午6:54:27
 */
public class ImageService {

    /**
     * 保存原尺寸图片和指定压缩图片，并返回压缩后图片地址
     *
     * @param originalImageUrl 原始图片url
     * @return
     * @date 2022年11月27日 下午6:55:49
     */
    public String saveAndGetScaleImage(String originalImageUrl, int width, int height) {
//		if (isFromImageServer(originalImageUrl)) {
//			return originalImageUrl;
//		}
        String imageResult = validAndGetImage(originalImageUrl);
        if (StringUtils.isBlank(imageResult)) {
            return ImageConsts.INEXISTENCE;
        }
        if (ImageConsts.IMAGE_TYPE_ERROR.equals(imageResult)) {
            return ImageConsts.IMAGE_TYPE_ERROR;
        }
        // save hbase
        // inputstream.read()关闭了流，重新构造图片流
        byte[] imgageBytes = Base64.decodeBase64(imageResult);
        InputStream imgInputStream = new ByteArrayInputStream(imgageBytes);
        ImageEntity imageEntity = transformImageEntity(imgInputStream, originalImageUrl);
        if (imageEntity == null) {
            return ImageConsts.IMAGE_TYPE_ERROR;
        }
        byte[] scaleImageByte = getScaleImageByte(imageEntity.getBinaryImage(), width, height);
        if (scaleImageByte == null) {
            return ImageConsts.IMAGE_SCALE_ERROR;
        }
        if (saveImage2Hbase(imageEntity, scaleImageByte)) {
            return genImageScaleUrl(imageEntity.getImageId());
        }
        return ImageConsts.INEXISTENCE;
    }

    /**
     * 原尺寸图片已存在，保存压缩图片，并返回压缩后图片地址
     */
    public String saveScaleImage(String originalImageUrl, int width, int height) {
        String rowkey = extractRowkey(originalImageUrl);
        if (StringUtil.isNullOrEmpty(rowkey)) {
            return ImageConsts.INEXISTENCE;
        }
        byte[] imageBytes = getOriginalImageByte(rowkey);
        if (imageBytes == null) {
            return ImageConsts.INEXISTENCE;
        }
        byte[] scaleImageByte = getScaleImageByte(imageBytes, width, height);
        if (scaleImageByte == null) {
            return ImageConsts.IMAGE_SCALE_ERROR;
        }
        if (saveImageScaleBytes2Hbase(rowkey, scaleImageByte)) {
            return genImageScaleUrl(rowkey);
        }
        return ImageConsts.INEXISTENCE;
    }

    private String extractRowkey(String originalImageUrl) {
        if (originalImageUrl.contains("=")) {
            return originalImageUrl.substring(originalImageUrl.indexOf('=') + 1);
        }
        return null;
    }

    private byte[] getOriginalImageByte(String rowkey) {
        Configuration conf = DolphinCrawlerConf.getInstance();
        try {
            HTable htable = new HTable(conf, ImageConsts.HBASE_TABLE_IMAGE);
            Get get = new Get(Bytes.toBytes(rowkey));
            Result rs = htable.get(get);
            byte[] OriginalImageByte = getValueAsByte(rs, ImageConsts.HBASE_FAMILY_IMAGE_INFO,
                    ImageConsts.HBASE_QUALIFIER_IMAGE_BINARY);
            htable.close();
            return OriginalImageByte;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    private byte[] getValueAsByte(Result result, String family,
                                  String qualifier) {
        return result.getValue(family.getBytes(), qualifier.getBytes());
    }


    private boolean saveImageScaleBytes2Hbase(String rowkey,
                                              byte[] scaleImageByte) {
        boolean isSuccess = false;
        try {
            Configuration conf = DolphinCrawlerConf.getInstance();
            HTable htable = new HTable(conf, ImageConsts.HBASE_TABLE_IMAGE);
            Put imagePut = new Put(Bytes.toBytes(rowkey));
            addImage2Put(imagePut, ImageConsts.HBASE_QUALIFIER_IMAGE_SCALE_BINARY,
                    scaleImageByte);//增加缩略图片
            htable.put(imagePut);
            htable.close();
            isSuccess = true;
        } catch (Exception e) {
            LOG.error("##image saveImageScaleBytes2Hbase error! rowkey:" + rowkey, e);
        }
        return isSuccess;
    }


    private boolean saveImage2Hbase(ImageEntity imageEntity,
                                    byte[] scaleImageByte) {
        boolean isSuccess = false;
        if (imageEntity == null) {
            LOG.info("##image is empty!");
            return isSuccess;
        }
        try {
            Configuration conf = DolphinCrawlerConf.getInstance();
            HTable htable = new HTable(conf, ImageConsts.HBASE_TABLE_IMAGE);
            Put imagePut = new Put(Bytes.toBytes(imageEntity.getImageId()));
            addImage2Put(imagePut, ImageConsts.HBASE_QUALIFIER_IMAGE_BINARY,
                    imageEntity.getBinaryImage());
            addImage2Put(imagePut, ImageConsts.HBASE_QUALIFIER_IMAGE_SCALE_BINARY,
                    scaleImageByte);//增加缩略图片
            addImage2Put(imagePut, ImageConsts.HBASE_QUALIFIER_IMAGE_URL,
                    imageEntity.getOriginalUrl());
            addImage2Put(imagePut, ImageConsts.HBASE_QUALIFIER_IMAGE_WIDTH,
                    imageEntity.getWidth() + "");
            addImage2Put(imagePut, ImageConsts.HBASE_QUALIFIER_IMAGE_HEIGHT,
                    imageEntity.getHeight() + "");
            htable.put(imagePut);
            htable.close();
            isSuccess = true;
        } catch (Exception e) {
            LOG.error("##image save2hbase error! url:" + imageEntity.getOriginalUrl(), e);
        }
        return isSuccess;
    }

    private byte[] getScaleImageByte(byte[] binaryImage, int width, int height) {
        InputStream imgInputStream = new ByteArrayInputStream(binaryImage);
        try {
            BufferedImage image = ImageIO.read(imgInputStream);
            Builder<BufferedImage> builder = null;
            int imageWidth = image.getWidth();
            int imageHeitht = image.getHeight();
            if ((float) width / height != (float) imageWidth / imageHeitht) {
                if (imageWidth > imageHeitht) {
                    image = Thumbnails.of(image).height(height)
                            .asBufferedImage();
                    builder = Thumbnails.of(image)
                            .sourceRegion(Positions.CENTER, width, height)
                            .size(width, height);
                } else {
                    image = Thumbnails.of(image).width(width)
                            .asBufferedImage();
                    builder = Thumbnails.of(image)
                            .sourceRegion(Positions.TOP_CENTER, width, height)
                            .size(width, height);
                }
            } else {
                builder = Thumbnails.of(image).size(183, 183);
            }

            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            builder.outputFormat("jpg").toOutputStream(baos);
            baos.flush();
            byte[] imageByte = baos.toByteArray();
            baos.close();
            return imageByte;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 保存图片并返回新的图片地址
     *
     * @param originalImageUrl 原始图片url
     * @return
     * @date 2022年11月27日 下午6:55:49
     */
    public String saveAndGetImage(String originalImageUrl) {
        if (isFromImageServer(originalImageUrl)) {
            return originalImageUrl;
        }
        String imageResult = validAndGetImage(originalImageUrl);
        if (StringUtils.isBlank(imageResult)) {
            return ImageConsts.INEXISTENCE;
        }
        if (ImageConsts.IMAGE_TYPE_ERROR.equals(imageResult)) {
            return ImageConsts.IMAGE_TYPE_ERROR;
        }
        // save hbase
        // inputstream.read()关闭了流，重新构造图片流
        byte[] imgageBytes = Base64.decodeBase64(imageResult);
        InputStream imgInputStream = new ByteArrayInputStream(imgageBytes);
        ImageEntity imageEntity = transformImageEntity(imgInputStream, originalImageUrl);
        if (saveImage2Hbase(imageEntity)) {
            return genImageUrl(originalImageUrl);
        }
        return ImageConsts.INEXISTENCE;
    }

    /**
     * 保存图片并返回新的图片地址
     *
     * @param originalImageUrl 原始图片url
     * @return key: url:xxxx
     * height:xxxx
     * width:xxxx
     * status:xxxx
     * @date 2022年11月27日 下午6:55:49
     */
    public Map<String, Object> saveAndGetImage2UrlAndSize(String originalImageUrl) {
        return saveAndGetImage2UrlAndSize(originalImageUrl, null);
    }

    /**
     * 保存图片并返回新的图片地址
     *
     * @param originalImageUrl 原始图片url
     * @return key: url:xxxx
     * height:xxxx
     * width:xxxx
     * status:xxxx
     * @date 2022年11月27日 下午6:55:49
     */
    public Map<String, Object> saveAndGetImage2UrlAndSize(String originalImageUrl, Map<String, String> property) {
        if (isFromImageServer(originalImageUrl)) {
            return imageGenMap(originalImageUrl, 0, 0, ImageConsts.NOT_CHANGE);
        }
        Map<String, Object> inHbase = checkImageInHbaseAndGetURLAndSize(originalImageUrl);
        if (inHbase != null) {
            return inHbase;
        }
        String imageResult = validAndGetImage(originalImageUrl, property);
        if (StringUtils.isBlank(imageResult)) {
            return imageGenMap(null, 0, 0, ImageConsts.INEXISTENCE);
        }
        if (ImageConsts.IMAGE_TYPE_ERROR.equals(imageResult)) {
            return imageGenMap(null, 0, 0, ImageConsts.IMAGE_TYPE_ERROR);
        }
        // save hbase
        // inputstream.read()关闭了流，重新构造图片流
        byte[] imgageBytes = Base64.decodeBase64(imageResult);
        InputStream imgInputStream = new ByteArrayInputStream(imgageBytes);
        ImageEntity imageEntity = transformImageEntity(imgInputStream, originalImageUrl);
        if (saveImage2Hbase(imageEntity)) {
            String url = genImageUrl(originalImageUrl);
            return imageGenMap(url, imageEntity.getHeight(), imageEntity.getWidth(), ImageConsts.IMAGE_TYPE_OK);
        }
        return imageGenMap(null, 0, 0, ImageConsts.INEXISTENCE);
    }

    //gen map
    public Map<String, Object> imageGenMap(String url, int height, int width, String status) {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put(ImageConsts.IMAGE_MAP_NAME.URL.getValue(), url);
        map.put(ImageConsts.IMAGE_MAP_NAME.HEIGHT.getValue(), height);
        map.put(ImageConsts.IMAGE_MAP_NAME.WIDTH.getValue(), width);
        map.put(ImageConsts.IMAGE_MAP_NAME.STATUS.getValue(), status);
        return map;
    }

    public Map<String, Object> checkImageInHbaseAndGetURLAndSize(String originalImageUrl) {
        ImageEntity imageEntity = hbaseDao.getImageFromHbaseNotContent(originalImageUrl);
        if (imageEntity == null) return null;
        String url = genImageUrl(originalImageUrl);
        return imageGenMap(url, imageEntity.getHeight(), imageEntity.getWidth(), ImageConsts.IMAGE_TYPE_OK);
    }

    /**
     * 保存图片并返回新的图片地址
     *
     * @param originalImageUrl
     * @param imageInputStream
     * @return
     * @date 2022年12月2日 下午5:48:15
     */
    public String saveAndGetImage(String originalImageUrl, InputStream imageInputStream) {
        if (imageInputStream == null) {
            return ImageConsts.INEXISTENCE;
        }
        if (isFromImageServer(originalImageUrl)) {
            return originalImageUrl;
        }
        // query from hbase
        if (hbaseDao.checkExistImage(originalImageUrl)) {
            return genImageUrl(originalImageUrl);
        }
        byte[] imageInByte;
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            IOUtils.copy(imageInputStream, baos);
            baos.flush();
            imageInByte = baos.toByteArray();
            baos.close();
            InputStream byteArrayInputStream = new ByteArrayInputStream(imageInByte);
            if (!isImage(byteArrayInputStream)) {
                LOG.info(String.format("##inputStream isn't image! url:%s", originalImageUrl));
                return ImageConsts.IMAGE_TYPE_ERROR;
            }
            if (imageInByte != null && imageInByte.length > 0) {
                ImageEntity imageEntity = transformImageEntity(
                        new ByteArrayInputStream(imageInByte), originalImageUrl);
                if (saveImage2Hbase(imageEntity)) {
                    return genImageUrl(originalImageUrl);
                }
            }
        } catch (Exception e) {
            LOG.error("##read inputstream error!", e);
        }
        return ImageConsts.INEXISTENCE;
    }

    /**
     * 通过原始图片url获取其在图片服务器地址
     *
     * @param originalImageUrl 原始图片url
     * @return
     * @date 2022年11月27日 下午7:00:25
     */
    public String getImageUrlByOriginalUrl(String originalImageUrl) {
        if (isFromImageServer(originalImageUrl)) {
            return originalImageUrl;
        }
        // query from hbase
        if (hbaseDao.checkExistImage(originalImageUrl)) {
            return genImageUrl(originalImageUrl);
        }
        // non't found
        return saveAndGetImage(originalImageUrl);
    }

    /**
     * 图片尺寸大小是否合适
     *
     * @param originalImageUrl
     * @param widthRelated
     * @param width
     * @param heightRelated
     * @param height
     * @return String
     * @date 2022年12月1日 下午1:43:58
     */
    public String filterImageDimension(String originalImageUrl, RelatedSymbol widthRelated,
                                       int width, RelatedSymbol heightRelated, int height) {
        ImageEntity imageEntity = getImageEntity(originalImageUrl);
        if (imageEntity == null) {
            LOG.info("##image is empty!");
            return ImageConsts.IMAGE_TYPE_ERROR;
        }
        // compare dimension
        if (isSuitableDimension(widthRelated, width, heightRelated, height, imageEntity)) {
            return ImageConsts.IMAGE_DIMENSION_SUITABLE;
        }
        return ImageConsts.IMAGE_DIMENSION_ERROR;
    }

    /**
     * 判断图片是否合适，若合适保存到hbase并返回新的图片地址
     *
     * @param originalImageUrl
     * @param widthRelated
     * @param width
     * @param heightRelated
     * @param height
     * @return
     * @date 2022年12月1日 下午3:35:12
     */
    public String filterDimensionAndSaveImage(String originalImageUrl, RelatedSymbol widthRelated,
                                              int width, RelatedSymbol heightRelated, int height) {
        ImageEntity imageEntity = getImageEntity(originalImageUrl);
        if (imageEntity == null) {
            LOG.info("##image is empty!");
            return ImageConsts.IMAGE_TYPE_ERROR;
        }
        // compare dimension
        if (isSuitableDimension(widthRelated, width, heightRelated, height, imageEntity)
                && saveImage2Hbase(imageEntity)) {
            return genImageUrl(originalImageUrl);
        }
        return ImageConsts.IMAGE_DIMENSION_ERROR;
    }

    private boolean isFromImageServer(String originalImageUrl) {
        String explainUrl = conf.get(ImageConsts.PARAM_IMAGEWEB_RESOURCE_DOMAIN);
        return originalImageUrl.startsWith(explainUrl);
    }

    private ImageEntity getImageEntity(String originalImageUrl) {
        ImageEntity imageEntity = hbaseDao.getImageFromHbase(originalImageUrl);
        // 不存在则下载
        if (imageEntity == null) {
            String imageResult = validAndGetImage(originalImageUrl);
            if (StringUtils.isBlank(imageResult)
                    || ImageConsts.IMAGE_TYPE_ERROR.equals(imageResult)) {
                return null;
            }
            // inputstream.read()关闭了流，重新构造图片流
            byte[] imgageBytes = Base64.decodeBase64(imageResult);
            InputStream imgInputStream = new ByteArrayInputStream(imgageBytes);
            imageEntity = transformImageEntity(imgInputStream, originalImageUrl);
        }
        return imageEntity;
    }

    /**
     * 尺寸是否合适
     *
     * @param widthRelated
     * @param width
     * @param heightRelated
     * @param height
     * @param imageEntity
     * @return
     * @date 2022年12月1日 下午3:26:00
     */
    private boolean isSuitableDimension(RelatedSymbol widthRelated, int width,
                                        RelatedSymbol heightRelated, int height, ImageEntity imageEntity) {
        int realWidth = imageEntity.getWidth();
        int realHeight = imageEntity.getHeight();
        return containsRelated(widthRelated, compare(realWidth, width))
                && containsRelated(heightRelated, compare(realHeight, height));
    }

    private RelatedSymbol compare(int one, int other) {
        int result = Integer.compare(one, other);
        if (result == 0) {
            return RelatedSymbol.EQUALS;
        } else if (result < 0) {
            return RelatedSymbol.LESSTHAN;
        } else {
            return RelatedSymbol.GREATERTHAN;
        }
    }

    private boolean containsRelated(RelatedSymbol one, RelatedSymbol other) {
        if (one == RelatedSymbol.GREATERTHAN_AND_EQUALS) {
            return other == RelatedSymbol.GREATERTHAN
                    || other == RelatedSymbol.GREATERTHAN_AND_EQUALS;
        }
        if (one == RelatedSymbol.LESSTHAN_AND_EQUALS) {
            return other == RelatedSymbol.LESSTHAN || other == RelatedSymbol.LESSTHAN_AND_EQUALS;
        }
        return one == other;
    }

    private String genImageUrl(String originalImageUrl) {
        String explainUrl = conf.get(ImageConsts.PARAM_IMAGEWEB_RESOURCE_DOMAIN);
        if (explainUrl.endsWith("/")) {
            explainUrl = explainUrl.substring(0, explainUrl.length() - 1);
        }
        return String.format("%s/getImage?id=%s", explainUrl,
                StringUtil.genMD5Val(originalImageUrl));
    }

    /**
     * 生成缩略图的url
     *
     * @return
     */
    private String genImageScaleUrl(String rowkey) {
        String explainUrl = conf.get(ImageConsts.PARAM_IMAGEWEB_RESOURCE_DOMAIN);
        if (explainUrl.endsWith("/")) {
            explainUrl = explainUrl.substring(0, explainUrl.length() - 1);
        }
        return String.format("%s/getImage?id=%s%s", explainUrl,
                rowkey, ImageConsts.IMAGE_SCALE_FLAG);
    }


    /**
     * 验证图片有效性（验证图片是否能正常访问，排除404, 500, 503的URL，是否是图片）,并获取图片字节
     *
     * @param originalImageUrl
     * @return
     * @date 2022年11月27日 下午7:08:04
     */
    private String validAndGetImage(String originalImageUrl) {
        return validAndGetImage(originalImageUrl, null);
    }

    /**
     * 验证图片有效性（验证图片是否能正常访问，排除404, 500, 503的URL，是否是图片）,并获取图片字节
     *
     * @param originalImageUrl
     * @return
     * @date 2022年11月27日 下午7:08:04
     */
    private String validAndGetImage(String originalImageUrl, Map<String, String> property) {
        String imageEncode = getImageWithRetry(originalImageUrl, property);
        if (StringUtils.isBlank(imageEncode)) {
            LOG.info("##image not found!");
            return null;
        }
        boolean isImageFlag = false;
        try {
            byte[] imgageBytes = Base64.decodeBase64(imageEncode);
            InputStream imageInputStream = new ByteArrayInputStream(imgageBytes);
            isImageFlag = isImage(imageInputStream);
        } catch (Exception e) {
            LOG.error("##validate image error!", e);
        }
        if (!isImageFlag) {
            LOG.info(String.format("##url:%s isn't image!", originalImageUrl));
            return ImageConsts.IMAGE_TYPE_ERROR;
        }
        return imageEncode;
    }

    public String getImageWithRetry(String originalImageUrl) {
        return getImageWithRetry(originalImageUrl, null);
    }

    public String getImageWithRetry(String originalImageUrl, Map<String, String> property) {
        int retry = conf.getInt("connection.try.time", 1);
        String imageBytes = null;
        int count = 1;
        while (retry-- > 0 && StringUtils.isBlank(imageBytes)) {
            imageBytes = getImageInputStream2String(originalImageUrl, property);
            if (StringUtils.isBlank(imageBytes)) {
                LOG.info(String.format("#getImageWithRetry retry count:%d,url:%s", count,
                        originalImageUrl));
            }
            count++;
        }
        return imageBytes;
    }

    public boolean isImage(InputStream imageInputStream) {
        boolean isImageFlag = false;
        try {
            // 是否是图片
            byte[] fileByte = new byte[28];
            imageInputStream.read(fileByte, 0, 28);
            if (fileByte != null && fileByte.length > 0) {
                String fileHead = FileTypeJudgeUtils.bytesToHexString(fileByte).toUpperCase();
                isImageFlag = FileTypeJudgeUtils.isImageFile(fileHead);
            }
        } catch (Exception e) {
            LOG.error("##judge file type is image error!");
        }
        return isImageFlag;
    }

    private String getImageInputStream2String(String originalImageUrl) {
        return getImageInputStream2String(originalImageUrl, null);
    }

    private String getImageInputStream2String(String originalImageUrl, Map<String, String> property) {
        CloseableHttpClient httpClient = null;
        HttpGet httpGet = null;
        try {
            httpClient = HttpClients.createDefault();
            httpGet = new HttpGet(originalImageUrl);
            httpGet.addHeader("Connection", "keep-alive");
            httpGet.addHeader("Cache-Control", "max-age=0");
            httpGet.addHeader("User-Agent", HEADER_USER_AGENT);
            httpGet.addHeader("Accept", HEADER_ACCEPT);
            if (property != null && !property.isEmpty()) {
                for (Map.Entry entry : property.entrySet()) {
                    String key = (String) entry.getKey();
                    String value = (String) entry.getValue();
                    httpGet.addHeader(key, value);
                }
            }
            RequestConfig.Builder builder = RequestConfig.custom();
            RequestConfig requestConfig = builder.setSocketTimeout(SOCKET_TIMEOUT)
                    .setConnectTimeout(CONNECTION_TIMEOUT).build();

            httpGet.setConfig(requestConfig);

            HttpResponse response = httpClient.execute(httpGet); // 执行GET请求
            int statusCode = response.getStatusLine().getStatusCode();
            //301 redirect: 301 代表永久性转移   302 redirect: 302 代表暂时性转移(Temporarily Moved )，
            if (statusCode == 200 || statusCode == 301 || statusCode == 302) {
                HttpEntity entity = response.getEntity(); // 获取响应实体
                if (null != entity) {
                    InputStream inputStream = entity.getContent();
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    IOUtils.copy(inputStream, baos);
                    baos.flush();
                    byte[] imageInByte = baos.toByteArray();
                    baos.close();
                    String base64 = new String(Base64.encodeBase64(imageInByte));
                    // Consume response content
                    EntityUtils.consume(entity);
                    return base64;
                }
            } else {
                LOG.info(String.format("##get image error url:%s ,statuscode:%d", originalImageUrl,
                        statusCode));
            }
        } catch (Exception e) {
            LOG.error("#get image error! url:" + originalImageUrl, e);
        } finally {
            if (httpGet != null) {
                httpGet.abort(); // release the resource
            }
            if (httpClient != null) {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    LOG.error("#get image error! url:" + originalImageUrl, e);
                }
            }
        }
        return null;
    }

    @SuppressWarnings("unused")
    private InputStream getImageInputStream(String originalImageUrl) {
        CloseableHttpClient httpClient = null;
        HttpGet httpGet = null;
        try {
            httpClient = HttpClients.createDefault();
            httpGet = new HttpGet(originalImageUrl);
            httpGet.addHeader("Connection", "keep-alive");
            httpGet.addHeader("Cache-Control", "max-age=0");
            httpGet.addHeader("User-Agent", HEADER_USER_AGENT);
            httpGet.addHeader("Accept", HEADER_ACCEPT);
            RequestConfig.Builder builder = RequestConfig.custom();
            RequestConfig requestConfig = builder.setSocketTimeout(SOCKET_TIMEOUT)
                    .setConnectTimeout(CONNECTION_TIMEOUT).build();

            httpGet.setConfig(requestConfig);

            HttpResponse response = httpClient.execute(httpGet); // 执行GET请求
            int statusCode = response.getStatusLine().getStatusCode();
            //301 redirect: 301 代表永久性转移   302 redirect: 302 代表暂时性转移(Temporarily Moved )，
            if (statusCode == 200 || statusCode == 301 || statusCode == 302) {
                HttpEntity entity = response.getEntity(); // 获取响应实体
                if (null != entity) {
                    return entity.getContent();
                }
            } else {
                LOG.info(String.format("##get image error url:%s ,statuscode:%d", originalImageUrl,
                        statusCode));
            }
        } catch (Exception e) {
            LOG.error("#get image error! url:" + originalImageUrl, e);
        } finally {
            if (httpGet != null) {
                // httpGet.abort(); // release the resource
            }
            if (httpClient != null) {
                try {
                    // httpClient.close();
                } catch (Exception e) {
                    LOG.error("#get image error! url:" + originalImageUrl, e);
                }
            }
        }
        return null;
    }

    private boolean saveImage2Hbase(ImageEntity imageEntity) {
        boolean isSuccess = false;
        if (imageEntity == null) {
            LOG.info("##image is empty!");
            return isSuccess;
        }
        try {
            Configuration conf = DolphinCrawlerConf.getInstance();
            HTable htable = new HTable(conf, ImageConsts.HBASE_TABLE_IMAGE);
            Put imagePut = new Put(Bytes.toBytes(imageEntity.getImageId()));
            addImage2Put(imagePut, ImageConsts.HBASE_QUALIFIER_IMAGE_BINARY,
                    imageEntity.getBinaryImage());
            addImage2Put(imagePut, ImageConsts.HBASE_QUALIFIER_IMAGE_URL,
                    imageEntity.getOriginalUrl());
            addImage2Put(imagePut, ImageConsts.HBASE_QUALIFIER_IMAGE_WIDTH,
                    imageEntity.getWidth() + "");
            addImage2Put(imagePut, ImageConsts.HBASE_QUALIFIER_IMAGE_HEIGHT,
                    imageEntity.getHeight() + "");
            htable.put(imagePut);
            htable.close();
//			hbaseDao.saveImage2Hbase(imagePut);
            isSuccess = true;
        } catch (Exception e) {
            LOG.error("##image save2hbase error! url:" + imageEntity.getOriginalUrl(), e);
        }
        return isSuccess;
    }

//    private String getImageType(InputStream imageInputStream) throws Exception {
//        byte[] data = IOUtils.toByteArray(imageInputStream);
//        String type = null;
//        if (data[0] == 'G' && data[1] == 'I' && data[2] == 'F') {
//            type = "gif";
//            return type;
//        } else {
//            return "png";
//       }
//    }

    private byte[] download(InputStream imageInputStream) throws Exception
    {
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = imageInputStream.read(buffer)) != -1) {
            outStream.write(buffer, 0, len);
        }
        imageInputStream.close();
        byte[] fileData = outStream.toByteArray();
        outStream.close();
        return fileData;
    }


    private ImageEntity transformImageEntity(InputStream imageInputStream, String originalImageUrl) {
        try {
//            BufferedImage bufferedImage = ImageIO.read(imageInputStream);
//            // convert BufferedImage to byte array
//            ByteArrayOutputStream baos = new ByteArrayOutputStream();
//            String type = getImageType(imageInputStream);
//            ImageIO.write(bufferedImage, type, baos);
//            baos.flush();
//            byte[] imageByte = baos.toByteArray();
//            baos.close();
            byte[] imageByte = download(imageInputStream);
            ImageEntity imageEntity = new ImageEntity();
            imageEntity.setBinaryImage(imageByte);
            imageEntity.setImageId(StringUtil.genMD5Val(originalImageUrl));
//            imageEntity.setHeight(bufferedImage.getHeight());
//            imageEntity.setWidth(bufferedImage.getWidth());
            imageEntity.setOriginalUrl(originalImageUrl);
            return imageEntity;
        } catch (Exception e) {
            LOG.error("##transform image entity error!", e);
        }
        return null;
    }

    private void addImage2Put(Put put, String qualifier, String value) {
        if (StringUtils.isBlank(value)) {
            return;
        }
        addImage2Put(put, qualifier, Bytes.toBytes(value));
    }

    private void addImage2Put(Put put, String qualifier, byte[] value) {
        if (value == null || value.length == 0) {
            return;
        }
        byte[] family = Bytes.toBytes(ImageConsts.HBASE_FAMILY_IMAGE_INFO);
        put.add(family, Bytes.toBytes(qualifier), value);
    }

    /**
     * 关系比较运算符
     */
    public static enum RelatedSymbol {
        EQUALS, // =
        LESSTHAN, // <
        GREATERTHAN, // >
        LESSTHAN_AND_EQUALS, // <=
        GREATERTHAN_AND_EQUALS;// >=
    }

    private ImageHbaseDao hbaseDao = null;
    private static final ImageService imageService = new ImageService();
    private static Logger LOG = Logger.getLogger(ImageService.class);
    private Configuration conf;
    private final static String HEADER_ACCEPT = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8";
    private final static String HEADER_USER_AGENT = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36";
    private final static int SOCKET_TIMEOUT = 10000;
    private final static int CONNECTION_TIMEOUT = 3000;

    private ImageService() {
        try {
            hbaseDao = ImageHbaseDao.getInstance();
            conf = DolphinCrawlerConf.getInstance();
        } catch (Exception e) {
            LOG.error("##imageService init error!", e);
        }
    }

    public static ImageService getInstance() {
        return imageService;
    }

}
